package com.smart.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.smart.pojo.Finance;
import com.smart.pojo.LoginUser;
import com.smart.pojo.Salary;
import com.smart.pojo.User;
import com.smart.mapper.UserMapper;
import com.smart.req.UserCondition;
import com.smart.resp.UserResp;
import com.smart.service.IFinanceService;
import com.smart.service.ISalaryService;
import com.smart.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.smart.utils.SMUtils;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.io.Serializable;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author lyj
 * @since 2023-04-19
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    ISalaryService salaryService;

    @Autowired
    IFinanceService financeService;

    @Override
    public UserDetails loadUserByUsername(String id) throws UsernameNotFoundException {
        User userEntity = baseMapper.selectById(id);
        if (userEntity != null) {
            //创建角色集合对象
            Collection<GrantedAuthority> authorities = new ArrayList<>();
            org.springframework.security.core.userdetails.User user = new org.springframework.security.core.userdetails.User(userEntity.getId().toString(), userEntity.getPassword(), authorities);
            return user;
        }
        return null;
    }

    @Override
    public int getCountByToday() {
        StringBuilder prefix = new StringBuilder("SH");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        prefix.append(sdf.format(new Date()));
        return baseMapper.getCountByPrefix(prefix.toString());
    }

    @Override
    public Page<UserResp> queryPageByCondition(UserCondition userCondition, Page<UserResp> userPage) {
        QueryWrapper<UserResp> wrapper = new QueryWrapper<>();
        wrapper.apply(" u.del_flag=0 ")
                .like(!ObjectUtils.isEmpty(userCondition.getUsername()), "u.username", userCondition.getUsername())
                .like(!ObjectUtils.isEmpty(userCondition.getUserCode()), "u.user_code", userCondition.getUserCode())
                .like(!ObjectUtils.isEmpty(userCondition.getWorkNum()), "u.work_num", userCondition.getWorkNum())
                .like(!ObjectUtils.isEmpty(userCondition.getPhone()), "u.phone", userCondition.getPhone())
                .eq(!ObjectUtils.isEmpty(userCondition.getStatus()), "u.status", userCondition.getStatus())
                .eq(!ObjectUtils.isEmpty(userCondition.getDeptId()), "d.id", userCondition.getDeptId());
        return baseMapper.queryPageByCondition(userPage, wrapper);
    }

    @Override
    public List<User> queryByRoleIdAndKeyword(Long roleId, String keyword) {
        List<User> userList = this.lambdaQuery()
                .eq(User::getRoleId, roleId)
                .eq(User::getStatus, 0)
                .and(!ObjectUtils.isEmpty(keyword),
                        qw -> qw.like(User::getUsername, keyword)
                                .or()
                                .like(User::getUserCode, keyword))
                .list();
        return userList;
    }

//    @Override
//    public List<User> queryByRoleIdAndKeyword(Long roleId, String keyword) {
//        QueryWrapper<User> wrapper = new QueryWrapper<>();
//        wrapper.apply("u.del_flag=0\n" +
//                "and ur.del_flag=0\n" +
//                "and r.del_flag=0\n" +
//                "and u.status=0\n" +
//                "and u.id=ur.user_id\n" +
//                "and ur.role_id=r.id")
//                .eq("r.id", roleId)
//                .and(!ObjectUtils.isEmpty(keyword),
//                        qw -> qw.like("u.username", keyword)
//                                .or().like("u.user_code", keyword));
//        return baseMapper.queryByRoleIdAndKeyword(wrapper);
//    }

//    @Override
//    public List<User> queryByKeywordExcludeRoleId(Long roleId, String keyword) {
//        List<UserRole> userRoles = userRoleService.lambdaQuery()
//                .eq(UserRole::getRoleId, roleId)
//                .list();
//        List<Long> associateUserIds = userRoles.stream().map(UserRole::getUserId).collect(Collectors.toList());
//        QueryWrapper<User> wrapper = new QueryWrapper<>();
//        wrapper.notIn(!associateUserIds.isEmpty(), "id", associateUserIds)
//                .and(!ObjectUtils.isEmpty(keyword),
//                        qw -> qw.like("username", keyword)
//                                .or().like("user_code", keyword));
//        return baseMapper.selectList(wrapper);
//    }

    @Override
    public boolean associate(Long roleId, Long[] userIds) {
        List<User> listByIds = this.listByIds(Arrays.asList(userIds));
        for (User user : listByIds) {
            user.setRoleId(roleId);
        }
        return this.updateBatchById(listByIds);
    }

    @Override
    public List<User> queryByKeywordExcludeRole(String keyword) {
        return this.lambdaQuery()
                .isNull(User::getRoleId)
                .and(!ObjectUtils.isEmpty(keyword),
                        qw -> qw.like(User::getUsername, keyword)
                                .or()
                                .like(User::getUserCode, keyword))
                .list();
    }

    @Override
    public UserResp queryById(Serializable id) {

        return baseMapper.queryById(id);
    }

    @Override
    public LoginUser queryUserInfoById(Long id) {

        return baseMapper.queryUserInfoById(id);
    }

    @Override
    public List<UserResp> queryAll() {

        return baseMapper.queryAll();
    }

    @Override
    public List<UserResp> queryByDeptId(Long departmentId) {

        return baseMapper.queryByDeptId(departmentId);
    }

    @Override
    public UserResp getUserInfoById(Long userId) {

        return baseMapper.getUserInfoById(userId);
    }

    @Override
    @Transactional
    public boolean saveOrUpdateUser(User user) {
        if (user.getId() == null) {
            //设置初始默认用户状态为入职
            user.setStatus(0);
            //设置初始默认密码123
            user.setPassword(new Md5Hash("123", user.getUserCode(), 3).toString());
            //生成唯一工号
            user.setWorkNum(SMUtils.getWorkNum(getCountByToday()));
            boolean save = this.save(user);

            //插入当月员工薪资记录，扣除当月入职前时间段的薪资
            Salary salary = new Salary();
            salary.setUserId(user.getId());
            salary.setBaseAmount(new BigDecimal(3000));
            salary.setSalaryDate(LocalDateTime.now());
            salary.setStatus(0);

            Calendar calendar = Calendar.getInstance();
            int day = calendar.get(Calendar.DAY_OF_MONTH);
            BigDecimal leaveAmount = salary.getBaseAmount()
                    .divide(new BigDecimal(30), 2, BigDecimal.ROUND_HALF_UP)
                    .multiply(new BigDecimal(day));
            salary.setLeaveAmount(leaveAmount);
            boolean save1 = salaryService.save(salary);
            return save & save1;
        } else {
            return this.updateById(user);
        }

    }

    @Override
    @Transactional
    public boolean dismissedById(Long id) {

        //计算该用户当月工资
        Salary salary = salaryService.getByUserId(id);
        Calendar calendar = Calendar.getInstance();
        int day = calendar.getActualMaximum(Calendar.DAY_OF_MONTH) - calendar.get(Calendar.DAY_OF_MONTH);
        BigDecimal leaveAmount = salary.getBaseAmount()
                .divide(new BigDecimal(30), 2, BigDecimal.ROUND_HALF_UP)
                .multiply(new BigDecimal(day));
        salary.setLeaveAmount(salary.getLeaveAmount().add(leaveAmount));
        //赔偿3月基本工资
        salary.setBonus(salary.getBonus().add(salary.getBaseAmount().multiply(new BigDecimal(3))));
        salary.setStatus(1);
        salaryService.updateById(salary);

        //保存辞退工资财务记录
        Finance finance = new Finance();
        finance.setType(0);
        finance.setAmount(new BigDecimal(0)
                .add(salary.getBaseAmount())
                .add(salary.getRdAmount())
                .add(salary.getBonus())
                .add(salary.getReimbursementAmount())
                .add(salary.getSalesAmount())
                .subtract(salary.getPenalty())
                .subtract(salary.getLeaveAmount()));
        financeService.save(finance);

        //更新用户状态为离职
        User user = this.getById(id);
        user.setStatus(2);
        boolean rs = this.updateById(user);

        return rs;
    }

    @Override
    public Page<UserResp> queryPageByDeptId(Long departmentId, Page<UserResp> userPage) {
        return baseMapper.queryPageByDeptId(departmentId, userPage);
    }

}
